"""
使用感知器神经网络算法来进行线性分类
感知器只能适用于线性分类，非线性分类无法使用
@todo 尚存在一些问题
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pylab import mpl

# 以下代码用于解决matplotlib无法显示中文字体的问题
mpl.rcParams['font.sans-serif'] = ['FangSong']  # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False  # 解决保存图像是负号'-'显示为方块的问题


class Perceptron:

    def __init__(self, eta=0.01, n_iter=10000):
        """
        初始化
        :param eta: 学习率
        :param n_iter: 权重向量训练次数
        """
        self.eta = eta
        self.n_iter = n_iter
        self._w = None
        self._errors = None

    def fit(self, x, y):
        """
        训练模型
        :param x: 输入的信号，x.shape[n_samples, n_features]
        :param y: 对应的正确输出
        :return:
        """
        self._w = np.zeros(1 + x.shape[1])  # 初始化所有权重向量为0
        self._errors = []  # 初始化错误次数

        for _ in range(self.n_iter):
            errors = 0
            # zip作用将列表结合
            # 如x = [[1,2,3], [4,5,6]], y = [7, 8],则zip(x, y) = [ [[1,2,3], 7], [[4,5,6], 8] ]
            for xi, target in zip(x, y):
                print(errors)
                # update = n * (y - y`)
                update = self.eta * (target - self.predict(xi))
                self._w[1:] += update * xi  # 更新权重
                self._w[0] = update  # 第一个为阈值，最后更新阈值
                # print(int(update != 0.0))
                errors += int(update != 0.0)  # 判断是否错误

            print("当前错误率(损失函数)为%d" % errors)
            self._errors.append(errors)  # 添加到错误列表，发生错误的次数应该会随着训练次数慢慢减少

    def net_input(self, x):
        """
        返回向量x和_w的点积
        :param x:
        :return:
        """
        return np.dot(x, self._w[1:]) + self._w[0]

    def predict(self, x):
        return np.where(self.net_input(x) >= 0.0, 1, -1)


def main():
    file = r"F:\MyExplore\Python\MachineLearning\resource\iris\iris_training.csv"
    df_all = pd.read_csv(file)  # 默认第一行为列名，如果需要读取第一行为数据时设置参数header=None
    df = df_all[df_all['species'] > 0]  # 只测试一分为二的情况
    # print(df.head(10))
    ys = df.loc[:]["species"].values
    print(ys)
    xs = df.iloc[:, [0, 2]].values
    print(xs)

    # 画图更直观
    # df_1 = df_all[df_all['species'] == 1]
    # xs_1 = df_1.iloc[:, [0, 2]].values
    # df_2 = df_all[df_all['species'] == 2]
    # xs_2 = df_2.iloc[:, [0, 2]].values
    # plt.scatter(xs_1[:, 0], xs_1[:, 1], color="red", marker='o', label="点值1")
    # plt.scatter(xs_2[:, 0], xs_2[:, 1], color="blue", marker='*', label="点值2")
    # plt.xlabel('花瓣长度')
    # plt.ylabel('花茎长度')
    # plt.legend(loc="upper left")
    # plt.show()

    # 训练模型
    classfiter = Perceptron()
    classfiter.fit(xs, ys)

if __name__ == "__main__":
    main()
